<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>音轨合并</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
        }
        /* 遮罩层 */ .overlay { display: none; position: fixed; top: 0; left: 0;
        width: 100%; height: 100%; background: rgba(0, 0, 0, 0.5); z-index: 1;
        } /* 弹窗样式 */ .modal { display: none; position: fixed; top: 50%; left: 50%;
        transform: translate(-50%, -50%); background: #fff; padding: 20px; box-shadow:
        0px 4px 6px rgba(0, 0, 0, 0.1); z-index: 2; width: 300px; text-align: center;
        } /* 关闭按钮 */ .close-btn { background-color: #f44336; color: white; border:
        none; padding: 5px 10px; cursor: pointer; border-radius: 5px; } .close-btn:hover
        { background-color: #d32f2f; }

        body {
            padding: 20px;
            background: #fff;
        }

        .container {
            /* max-width: 1200px; */
            width: 100%;
            margin: 0 auto;
        }

        .info-banner {
            background-color: #f0f7ff;
            border: 1px solid #e1eeff;
            border-radius: 4px;
            padding: 12px;
            margin-bottom: 20px;
            color: #1a73e8;
            display: flex;
            align-items: center;
            gap: 8px;
        }

        .info-icon {
            width: 16px;
            height: 16px;
            background-color: #1a73e8;
            border-radius: 50%;
            color: white;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 12px;
        }

        .input-section {
            display: flex;
            align-items: center;
            gap: 10px;
            margin-bottom: 20px;
        }

        .button {
            padding: 8px 16px;
            border: none;
            border-radius: 4px;
            background: #1a73e8;
            color: white;
            cursor: pointer;
            font-size: 14px;
            white-space: nowrap;
        }

        .text-input {
            flex: 1;
            padding: 8px;
            border: 1px solid #ddd;
            border-radius: 4px;
            color: #999;
        }

        .input-label {
            color: #666;
            white-space: nowrap;
        }

        .stats {
            color: #666;
            font-size: 14px;
            margin: 10px 0;
        }

        .table {
            width: 100%;
            border-collapse: collapse;
            margin-top: 10px;
        }

        .table th {
            background: #f5f5f5;
            text-align: left;
            padding: 12px;
            font-weight: normal;
            color: #666;
            font-size: 14px;
        }

        .empty-state {
            text-align: center;
            padding: 40px;
            color: #999;
        }

        .empty-icon {
            width: 60px;
            height: 60px;
            margin: 0 auto 10px;
            background-color: #f5f5f5;
            border-radius: 50%;
            display: flex;
            align-items: center;
            justify-content: center;
        }
    </style>
    <script src="qrc:///qtwebchannel/qwebchannel.js"></script>
</head>
<body>
<div class="container">
    <div id="overlay" class="overlay" onclick="closeModal()"></div>

    <div id="modal" class="modal">
        <p id="message">消息弹窗</p>
        <!-- TODO: 调整消息弹窗样式 -->
        <button class="close-btn" onclick="closeModal()">关闭</button>
    </div>

    <div class="info-banner">
        <div class="info-icon">i</div>
        功能说明：该功能可以合并多个音视频文件的音轨，并输出音频文件
    </div>


    <div class="input-group">
        <label>素材目录:</label>
        <label for="clipInput"></label><input type="text" id="clipInput" placeholder="请选择视频文件/文件夹"
                                              onclick="clipInput('clipInput')" value="">
        <button class="btn btn-primary" onclick="importFile()">导入音视频文件</button>
    </div>
    <div class="input-group">
        <label>导出目录:</label>
        <label for="clipOutput"></label><input type="text" onclick="chooseFolder('clipOutput')" id="clipOutput"
                                               placeholder="请选择文件夹" value="">
    </div>

    <div class="button-group">
        <button class="btn btn-primary" id="open-file-btn" onclick="openFile('clipOutput')">打开文件夹</button>
        <button class="btn btn-primary" onclick="start_work()">开始任务</button>
    </div>

    <div class="status-bar">
        已选择<span class="red-text" id="select_video_count_total">0</span>个视频文件(最多可选择10个)
        <input type="checkbox" id="selectAll" class="selectAll" onchange="selectAll()">
        <label for="selectAll">选择全部</label>
        <div class="file-list">
            <table>
                <thead>
                <tr>
                    <td>选择</td>
                    <th>序号</th>
                    <th>文件名</th>
                    <th>时长</th>
                    <th>大小</th>
                    <th>合成时长</th>
                    <th>音量</th>
                </tr>
                </thead>
                <tbody id="shotListBody">
                <!-- 动态生成的行将被插入这里 -->
                </tbody>
            </table>
        </div>
    </div>
</div>
<script type="text/javascript">
    document.addEventListener("DOMContentLoaded", function () {

        let items = [];

        new QWebChannel(parent.qt.webChannelTransport, function (channel) {
            Bridge = channel.objects.Bridge;

            Bridge.started.connect(function (msg) {
                showModal(msg)
            });
            Bridge.failed.connect(function (msg) {
                showModal(msg)
            });
            Bridge.finished.connect(function (message) {
                showModal(message);
            });


            /*  文件操作方法  */
            // 选择文件夹
            window.chooseFolder = function (eid) {
                Bridge.choose_folder(eid);
            };
            // 打开文件或者文件夹
            window.openFile = function (eid) {
                let path = document.getElementById(eid).value;
                if (path) {
                    Bridge.open_file(path);
                }
            };

            // 选择的文件夹信号槽
            Bridge.select_folder_result.connect(function (eid, path) {
                document.getElementById(eid).value = path;
            });
            // 返回智能分镜目录
            Bridge.select_files_result.connect(function (eid, files, count) {
                // 渲染基础合成分镜列表
                const tbody = document.getElementById('shotListBody');
                if (!tbody) {
                    return;
                }
                let files_list = [];

                for (let file_item of files) {
                    // 按照file去重
                    if (items.find(i => i.file === file_item.file)) {
                        continue;
                    }
                    let data_id = items.length + 1;
                    files_list.push(`
                        <tr data-id="${data_id}">
                            <td><label>
                                <input type="checkbox" class="row-check" value="${file_item.file}">
                            </label></td>
                            <td>${data_id}</td>
                            <td>${file_item.file}</td>
                            <td>${file_item.duration}秒</td>
                            <td>${file_item.size}</td>
                            <td><input type="number" class="duration-input" value="${parseFloat(file_item.duration)}" min="1" max="${parseFloat(file_item.duration)}" step="0.01"></td>
                            <td><input type="number" class="volume-input" value="1.0" min="0.01" max="1.0" step="0.01"></td>
                        </tr>
                    `);
                    file_item.status = false;
                    file_item.clip = parseFloat(file_item.duration);
                    file_item.volume = 1.0;
                    items.push(file_item);
                }
                tbody.innerHTML = tbody.innerHTML + files_list.join('');
                bindEventListeners();
            });

            window.clipInput = function () {
                Bridge.choose_folder_and_read_video_and_audio_files("clipInput")
            };
            window.importFile = function () {
                Bridge.choose_video_and_audio_files("clipInput");
            }

            /*  操作逻辑  */
            // 开始分镜
            window.start_work = function () {
                let tasks = []
                for (let item of items) {
                    if (item.status) {
                        tasks.push({
                            file: item.file,
                            duration: item.clip,
                            volume: item.volume
                        })
                    }
                }
                if (tasks.length === 0) {
                    showModal("请选择视频文件");
                    return;
                }
                let output_path = document.getElementById("clipOutput").value;
                if (!output_path) {
                    showModal("请选择导出目录");
                    return;
                    }
                let task_items = {
                    "task": "合并音频",
                    "tasks": tasks,
                    "output_path": output_path
                }
                Bridge.start_worker(JSON.stringify(task_items));
            };
        });
        // 开始任务
        let selected_video_count_elm = document.getElementById("select_video_count_total");

        window.showModal = function (message) {
            document.getElementById("message").innerText = message;
            document.getElementById("overlay").style.display = "block";
            document.getElementById("modal").style.display = "block";
        };

        window.closeModal = function () {
            document.getElementById("overlay").style.display = "none";
            document.getElementById("modal").style.display = "none";
        };


        // 选择全部
        window.selectAll = function () {
            let selectAllCheckbox = document.getElementById("selectAll");
            let rowCheckboxes = document.querySelectorAll(".row-check");
            rowCheckboxes.forEach(checkbox => {
                checkbox.checked = selectAllCheckbox.checked;
            });
            if (selectAllCheckbox.checked) {
                selected_video_count_elm.innerText = rowCheckboxes.length;
                // 从items中计算总时长
                for (let item of items) {
                    item.status = true;
                }
            } else {
                for (let item of items) {
                    item.status = false;
                }
                selected_video_count_elm.innerText = 0;
            }
        };

        window.update_total = function () {
            let total_count = 0;
            for (let item of items) {
                if (item.status) {
                    total_count++;
                }
            }
            selected_video_count_elm.innerText = total_count;
        };

        window.getShotIdFromRow = function (element) {
            return element.closest('tr').getAttribute('data-id');
        };
        window.updateShotData = function (id, field, value) {
                const shot = items.find(item => parseInt(item.id) === parseInt(id));
                if (shot) {
                    shot[field] = value;
                }
            };

        // 监听单个视频选择
        window.bindEventListeners = function () {
            document.querySelectorAll(".row-check").forEach(checkbox => {
                checkbox.addEventListener("change", function (event) {
                    if (checkbox.checked) {
                        for (let item of items) {
                            if (item.file === event.target.value) {
                                item.status = true;
                            }
                        }
                    } else {
                        for (let item of items) {
                            if (item.file === event.target.value) {
                                item.status = false;
                            }
                        }
                    }
                    update_total();
                });
            });

            document.querySelectorAll(".duration-input").forEach(input => {
                input.addEventListener("input", function (event) {
                    const data_id = getShotIdFromRow(event.target);
                    const newName = event.target.value;
                    updateShotData(data_id, 'clip', newName);
                });
            });

            document.querySelectorAll(".volume-input").forEach(input => {
                input.addEventListener("input", function (event) {
                    const data_id = getShotIdFromRow(event.target);
                    const newName = event.target.value;
                    updateShotData(data_id, 'volume', newName);
                });
            });
        };
    });
</script>
</body>
</html> 